package com.lpit.crawler;

import com.lpit.CrawlerCookie;

import com.lpit.CrawlerProxy;
import com.lpit.pojo.CrawlerHtml;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeOptions;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Set;

@Slf4j
public class SeleniumClient {

    private static final long sleepTime = 1000;

    private static final long outTime = 10000;

    private static final ResourceBundle resourceBundle = ResourceBundle.getBundle("crawler");

    /*创建Chrome驱动*/
    private SeleniumDriver initChromeDriver(Proxy proxy) {
        SeleniumDriver seleniumDriver = new SeleniumDriver();
        /*创建服务（驱动）*/
        ChromeDriverService chromeDriverService = new ChromeDriverService.Builder()
                .usingDriverExecutable(new File(resourceBundle.getString("webdriver.chrome.driver")))
                .usingAnyFreePort()
                .build();
        ChromeOptions chromeOptions = this.getChromeOptions(proxy);
        //启动一个 chrome 实例
        WebDriver webDriver = new ChromeDriver(chromeDriverService, chromeOptions);
        seleniumDriver.setWebDriver(webDriver);
        seleniumDriver.setChromeDriverService(chromeDriverService);
        log.info("WebDriver启动成功");
        return seleniumDriver;
    }

    private ChromeOptions getChromeOptions(Proxy proxy) {
        //获取chrome驱动的位置
        ChromeOptions chromeOptions = new ChromeOptions();
        /*设置无头模式*/
        chromeOptions.setHeadless(true);
        //启动代理
        if (null != proxy) {
            chromeOptions.setProxy(proxy);
        }
        return chromeOptions;
    }

    /**
     * 处理请求
     *
     * @param url            需要访问的URL
     * @param proxy          处理的代理请求
     * @param chromeCallback 执行完成的回调
     */
    private void handel(String url, Proxy proxy, ChromeCallback chromeCallback) {
        SeleniumDriver seleniumDriver = null;
        if (StringUtils.isNotEmpty(url) && null != chromeCallback) {
            try {
                seleniumDriver = this.initChromeDriver(proxy);
                if (null != seleniumDriver && null != seleniumDriver.getWebDriver()) {
                    chromeCallback.callBack(seleniumDriver.getWebDriver());
                }
            } catch (Exception ignored) {
                throw new RuntimeException("异常");
            } finally {
                /*此处调用关闭驱动方法*/
                closeChrome(seleniumDriver);
            }
        }
    }

    public CrawlerHtml getCrawler(String url, CrawlerProxy crawlerProxy, String cookieName) {
        CrawlerHtml crawlerHtml = new CrawlerHtml(url, crawlerProxy);
        Proxy proxy = null;
        if (null != crawlerProxy) {
            proxy = CrawlerProxyFactory.getSeleniumProxy(crawlerProxy);

        }
        handel(url, proxy, driver -> {
            driver.get(url);
            List<CrawlerCookie> crawlerCookieList = delayed(driver, cookieName);
            crawlerHtml.setCrawlerCookies(crawlerCookieList);
            crawlerHtml.setHtml(driver.getPageSource());
        });
        return crawlerHtml;
    }

    private List<CrawlerCookie> delayed(WebDriver driver, String cookieName) {

        Object value = DelayedUtils.delayed(new DelayedCallback() {
            @Override
            public List<CrawlerCookie> callBack(long time) {/*time用处？*/
                Set<Cookie> cookieSet = driver.manage().getCookies();
                return getCrawlerCookie(cookieSet);
            }

            @Override
            public boolean isExist() {
                Set<Cookie> cookieSet = driver.manage().getCookies();
                if (null != cookieSet && !cookieSet.isEmpty()) {
                    for (Cookie cookie : cookieSet) {
                        if (cookie.getName().equals(cookieName)) {
                            return true;
                        }
                    }
                }
                return false;
            }

            @Override
            public long sleepTime() {
                return sleepTime;
            }

            @Override
            public long timeOut() {
                return outTime;
            }
        });
        return (List<CrawlerCookie>) value;
    }

    /*获取 Cookie*/
    private List<CrawlerCookie> getCrawlerCookie(Set<Cookie> cookieSet) {
        List<CrawlerCookie> crawlerCookieList = new ArrayList<CrawlerCookie>();
        for (Cookie cookie : cookieSet) {
            CrawlerCookie crawlerCookie = fillCrawlerCookie(cookie);
            if (null != crawlerCookie) {
                crawlerCookieList.add(crawlerCookie);
            }
        }
        return crawlerCookieList;
    }

    private CrawlerCookie fillCrawlerCookie(Cookie cookie) {
        CrawlerCookie crawlerCookie = new CrawlerCookie();
        crawlerCookie.setDomain(cookie.getDomain());
        crawlerCookie.setPath(cookie.getPath());
        crawlerCookie.setName(cookie.getName());
        crawlerCookie.setValue(cookie.getValue());
        crawlerCookie.setExpire(cookie.getExpiry());
        return crawlerCookie;
    }

    /*关闭浏览器*/
    private void closeChrome(SeleniumDriver seleniumDriver) {
        if (null != seleniumDriver) {
            WebDriver webDriver = seleniumDriver.getWebDriver();
            ChromeDriverService chromeDriverService = seleniumDriver.getChromeDriverService();
            try {
                webDriver.quit();
            } finally {
                if (null != chromeDriverService) {
                    chromeDriverService.stop();
                }
            }
            if (null != chromeDriverService) {
                if (chromeDriverService.isRunning()) {
                    chromeDriverService.stop();
                }
            }
        }

    }


    interface ChromeCallback {
        /*延时调用*/
        public void callBack(WebDriver driver);
    }

    class SeleniumDriver {

        private WebDriver webDriver;
        private ChromeDriverService chromeDriverService;

        public WebDriver getWebDriver() {
            return webDriver;
        }

        public void setWebDriver(WebDriver webDriver) {
            this.webDriver = webDriver;
        }

        public ChromeDriverService getChromeDriverService() {
            return chromeDriverService;
        }

        public void setChromeDriverService(ChromeDriverService chromeDriverService) {
            this.chromeDriverService = chromeDriverService;
        }
    }
}

